﻿using MvCamCtrl.NET;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Vision.Camera.Base;

namespace Vision.Camera.HK
{
    public class CameraHK : ICamera
    {
        [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
        public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);

        private MyCamera m_pMyCamera = new MyCamera();
        /// <summary>
        /// 相机列表
        /// </summary>
        static MyCamera.MV_CC_DEVICE_INFO_LIST m_pDeviceList = new MyCamera.MV_CC_DEVICE_INFO_LIST();
        /// <summary>
        ///  设备信息
        /// </summary>
        MyCamera.MV_CC_DEVICE_INFO Device;
        /// <summary>
        /// 相机回调
        /// </summary>
        MyCamera.cbOutputExdelegate ImageCallback;
        IntPtr m_BufForDriver = IntPtr.Zero;
        UInt32 m_nBufSizeForDriver = 0;
        MyCamera.MV_PIXEL_CONVERT_PARAM stConvertInfo = new MyCamera.MV_PIXEL_CONVERT_PARAM();
        IntPtr m_ConvertDstBuf = IntPtr.Zero;
        UInt32 m_nConvertDstBufLen = 0;
        PixelFormat m_bitmapPixelFormat = PixelFormat.DontCare;
        private AutoResetEvent autoResetEvent = new AutoResetEvent(false);
        Bitmap m_bitmap = null;
        public string Name => throw new NotImplementedException();

        public event EventHandler<ImageArgs> OnReceiveImg;

        public void CloseCam()
        {
            int nRet;
            nRet = m_pMyCamera.MV_CC_CloseDevice_NET();
            if (MyCamera.MV_OK != nRet)
            {
                return;
            }
            nRet = m_pMyCamera.MV_CC_DestroyDevice_NET();
            if (MyCamera.MV_OK != nRet)
            {
                return;
            }
        }

        public long GetExposureTime()
        {
            MyCamera.MVCC_FLOATVALUE stParam = new MyCamera.MVCC_FLOATVALUE();
            int nRet = m_pMyCamera.MV_CC_GetFloatValue_NET("ExposureTime", ref stParam);
            if (MyCamera.MV_OK == nRet)
            {
                return Convert.ToInt64(stParam.fCurValue.ToString());
            }
            return 0;
        }

        public double GetGain()
        {
            MyCamera.MVCC_FLOATVALUE stParam = new MyCamera.MVCC_FLOATVALUE();
            int nRet = m_pMyCamera.MV_CC_GetFloatValue_NET("Gain", ref stParam);
            if (MyCamera.MV_OK == nRet)
            {
                return stParam.fCurValue;
            }
            return 0;
        }
        public bool OpenByIP(string cameraIP,string netIP)
        {
            Device = new MyCamera.MV_CC_DEVICE_INFO();
            MyCamera.MV_GIGE_DEVICE_INFO stGigEDev = new MyCamera.MV_GIGE_DEVICE_INFO();
            stGigEDev.nCurrentIp = ParseIP(cameraIP);
            stGigEDev.nNetExport = ParseIP(netIP);
            Device.nTLayerType = MyCamera.MV_GIGE_DEVICE;// ch:仅支持GigE相机 | en:Only support GigE camera
            
            int size = Marshal.SizeOf(stGigEDev);
            IntPtr buffer = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(stGigEDev, buffer, false);

            Device.SpecialInfo.stGigEInfo = new byte[540];
            Marshal.Copy(buffer, Device.SpecialInfo.stGigEInfo, 0, size);

            int Ret = m_pMyCamera.MV_CC_CreateDevice_NET(ref Device);
            return OpenCam();
           
        }
        uint ParseIP(string str)
        {
            uint ip = 0;
            string[] vecs = str.Split('.');
            if (vecs.Length == 4)
            {
                for (int i = 0; i < 4; i++)
                {
                    ip += uint.Parse(vecs[i]) << ((3 - i) * 8);
                }
            }
            return ip;
        }
        public bool OpenCam()
        {
            int nRet = -1;
            nRet = m_pMyCamera.MV_CC_OpenDevice_NET();
            if (MyCamera.MV_OK != nRet)
            {
                m_pMyCamera.MV_CC_DestroyDevice_NET();
                //ShowErrorMsg("Device open fail!", nRet);
                return false;
            }

            // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
            if (Device.nTLayerType == MyCamera.MV_GIGE_DEVICE)
            {
                int nPacketSize = m_pMyCamera.MV_CC_GetOptimalPacketSize_NET();
                if (nPacketSize > 0)
                {
                    nRet = m_pMyCamera.MV_CC_SetIntValue_NET("GevSCPSPacketSize", (uint)nPacketSize);
                    if (nRet != MyCamera.MV_OK)
                    {
                        Console.WriteLine("Warning: Set Packet Size failed {0:x8}", nRet);
                    }
                }
                else
                {
                    Console.WriteLine("Warning: Get Packet Size failed {0:x8}", nPacketSize);
                }
            }
            // ch:注册回调函数 | en:Register image callback


            //if(pBufForSaveImage != IntPtr.Zero)
            //{

            //}

            //pBufForSaveImage = Marshal.AllocHGlobal((int)(pFrameInfo.nWidth * pFrameInfo.nHeight * 3 + 2048));
            ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);
            nRet = m_pMyCamera.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
            nRet = NecessaryOperBeforeGrab();
            m_pMyCamera.MV_CC_SetEnumValue_NET("AcquisitionMode", 2);// ch:工作在连续模式 | en:Acquisition On Continuous Mode
            m_pMyCamera.MV_CC_SetEnumValue_NET("TriggerMode", 1);//初始设定为触发模式
            m_pMyCamera.MV_CC_SetEnumValue_NET("TriggerSource", 7);//初始设定为软触发
            m_pMyCamera.MV_CC_StartGrabbing_NET();//Start启动
            return true;
        }

        public Bitmap ReadImage(int millisecondsTimeout=1000)
        {
            if (autoResetEvent.WaitOne(millisecondsTimeout))
                return m_bitmap;
            else
                return null;
        }

        public List<ICamera> Scan(string brand)
        {
            int nRet;
            List<ICamera> cameras = new List<ICamera>();
            // ch:创建设备列表 en:Create Device List
            System.GC.Collect();
            //Cameralist.Clear();
            nRet = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref m_pDeviceList);
            if (0 != nRet)
            {
                ShowErrorMsg("Enumerate devices fail!", 0);
                return cameras;
            }

            // ch:在窗体列表中显示设备名 | en:Display device name in the form list
            for (int i = 0; i < m_pDeviceList.nDeviceNum; i++)
            {
                MyCamera.MV_CC_DEVICE_INFO device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_pDeviceList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));
                if (device.nTLayerType == MyCamera.MV_GIGE_DEVICE)
                {
                    IntPtr buffer = Marshal.UnsafeAddrOfPinnedArrayElement(device.SpecialInfo.stGigEInfo, 0);
                    MyCamera.MV_GIGE_DEVICE_INFO gigeInfo = (MyCamera.MV_GIGE_DEVICE_INFO)Marshal.PtrToStructure(buffer, typeof(MyCamera.MV_GIGE_DEVICE_INFO));
                    if (gigeInfo.chModelName.Contains("ID"))
                    {
                        continue;
                    }
                    if (gigeInfo.chManufacturerName == "Hikvision" || gigeInfo.chManufacturerName == "Hikrobot" || gigeInfo.chManufacturerName == "GEV"/* || gigeInfo.chManufacturerName == "Huaray Technology"*/)
                    {
                        string name;
                        if (gigeInfo.chModelName != "")
                        {
                            name = "HK-G: " + gigeInfo.chUserDefinedName + " (" + gigeInfo.chSerialNumber + ")";
                        }
                        else
                        {
                            name = "HK-G: " + gigeInfo.chManufacturerName + " " + gigeInfo.chModelName + " (" + gigeInfo.chSerialNumber + ")";
                        }
                        CameraHK hKvision = new CameraHK();
                        hKvision.Device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_pDeviceList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));
                        //hKvision.m_pMyCamera = new MyCamera();
                        int Ret = hKvision.m_pMyCamera.MV_CC_CreateDevice_NET(ref hKvision.Device);
                        if (MyCamera.MV_OK != Ret)
                        {
                            break;
                        }
                        cameras.Add(hKvision);
                        //hKvision.OpenCam();//打开相机
                        //hKvision.imageoutput.devicename = name;
                        //CameraBaseList[name] = hKvision;
                        //CameraBaseList[name].CamBrand = CamBrand;
                        //Cameralist.Add(name);
                    }
                }
                else if (device.nTLayerType == MyCamera.MV_USB_DEVICE)
                {
                    IntPtr buffer = Marshal.UnsafeAddrOfPinnedArrayElement(device.SpecialInfo.stUsb3VInfo, 0);
                    MyCamera.MV_USB3_DEVICE_INFO usbInfo = (MyCamera.MV_USB3_DEVICE_INFO)Marshal.PtrToStructure(buffer, typeof(MyCamera.MV_USB3_DEVICE_INFO));
                    if (usbInfo.chManufacturerName == "Hikvision" || usbInfo.chManufacturerName == "Hikrobot" || usbInfo.chManufacturerName == "GEV")
                    {
                        string name;
                        if (usbInfo.chUserDefinedName != "")
                        {
                            name = "HK-U: " + usbInfo.chUserDefinedName + " (" + usbInfo.chSerialNumber + ")";
                        }
                        else
                        {
                            name = "HK-U: " + usbInfo.chManufacturerName + " " + usbInfo.chModelName + " (" + usbInfo.chSerialNumber + ")";
                        }
                        CameraHK hKvision = new CameraHK();
                        hKvision.Device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_pDeviceList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));
                        //hKvision.m_pMyCamera = new MyCamera();
                        int Ret = hKvision.m_pMyCamera.MV_CC_CreateDevice_NET(ref hKvision.Device);
                        if (MyCamera.MV_OK != Ret)
                        {

                            break;
                        }
                        cameras.Add(hKvision);
                        //hKvision.OpenCam();//打开相机
                        //hKvision.imageoutput.devicename = name;
                        //CameraBaseList[name] = hKvision;
                        //CameraBaseList[name].CamBrand = CamBrand;
                        //Cameralist.Add(name);
                    }
                }
            }

            return cameras;
        }

        public void SetHardtrig()
        {
            m_pMyCamera.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_LINE2);
        }
        public void ReSetHardtrig()
        {
            m_pMyCamera.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE);
            //IsHardWareTrig = false;
        }

        public void SetExposureTime(long value)
        {
            m_pMyCamera.MV_CC_SetEnumValue_NET("ExposureAuto", 0);
            int nRet = m_pMyCamera.MV_CC_SetFloatValue_NET("ExposureTime", value);
            if (nRet != MyCamera.MV_OK)
            {
                ShowErrorMsg("Set Exposure Time Fail!", nRet);
            }
        }

        public void SetGain(double value)
        {
            m_pMyCamera.MV_CC_SetEnumValue_NET("GainAuto", 0);
            int nRet = m_pMyCamera.MV_CC_SetFloatValue_NET("Gain", (float)value);
            if (nRet != MyCamera.MV_OK)
            {
                ShowErrorMsg("Set Gain Fail!", nRet);
            }
        }

        public bool Snap()
        {
            int nRet = m_pMyCamera.MV_CC_SetCommandValue_NET("TriggerSoftware");
            if (nRet != MyCamera.MV_OK)
            {
                //ShowErrorMsg("Sanp Fail!", nRet);
                return false;
            }
            return true;
        }

        public bool StartGrabbing()
        {
            int nRet = m_pMyCamera.MV_CC_SetEnumValue_NET("TriggerMode", 0);
            if (nRet != MyCamera.MV_OK)
            {
                ShowErrorMsg("Start Grabbing Fail!", nRet);
                return false;
            }
            //IsGrabbing = true;
            return true;
        }

        public bool StopGrabbing()
        {
            int nRet = m_pMyCamera.MV_CC_StopGrabbing_NET();
            nRet = m_pMyCamera.MV_CC_SetEnumValue_NET("TriggerMode", 1);
            nRet = m_pMyCamera.MV_CC_SetEnumValue_NET("TriggerSource", 7);
            nRet = m_pMyCamera.MV_CC_StartGrabbing_NET();
            if (nRet != MyCamera.MV_OK)
            {
                ShowErrorMsg("Stop Grabbing Fail!", nRet);
                return false;
            }
            //IsGrabbing = false;
            return true;
        }

        /// <summary>
        /// 回调函数
        /// </summary>
        /// <param name="pData">图像数据指针</param>
        /// <param name="pFrameInfo">解释</param>
        /// <param name="pUser"></param>
        public void ImageCallbackFunc(IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
        {
            //if (VisionTool_Setting.HalconImage_Enable)
            //if (HalconImage_Enable)
            //{
            //    try
            //    {
            //        if (pFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8)
            //        {
            //            //HOperatorSet.GenImage1(out hPylonImage, "byte", (HTuple)grabResult.Width, (HTuple)grabResult.Height, (HTuple)latestFrameAddress);
            //            m_Image.GenImage1("byte", pFrameInfo.nWidth, pFrameInfo.nHeight, pData);

            //        }
            //        else
            //        {
            //            if (pFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed)
            //            {
            //                //如果彩色图像是RGB8格式，则可以直接利用GenImageInterleaved算子来构建图像
            //                m_Image.GenImageInterleaved(pData, "rgb", (int)pFrameInfo.nWidth, (int)pFrameInfo.nHeight, 0, "byte", (int)pFrameInfo.nWidth, (int)pFrameInfo.nHeight, 0, 0, -1, 0);
            //            }
            //            else
            //            {
            //                //如果彩色图像不是RGB8格式，则需要将图像格式转换为RGB8。
            //                IntPtr pBufForSaveImage = IntPtr.Zero;
            //                if (pBufForSaveImage == IntPtr.Zero)
            //                {
            //                    pBufForSaveImage = Marshal.AllocHGlobal((int)(pFrameInfo.nWidth * pFrameInfo.nHeight * 3 + 2048));
            //                }
            //                MyCamera.MV_PIXEL_CONVERT_PARAM stConverPixelParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();
            //                stConverPixelParam.nWidth = pFrameInfo.nWidth;
            //                stConverPixelParam.nHeight = pFrameInfo.nHeight;
            //                stConverPixelParam.pSrcData = pData;
            //                stConverPixelParam.nSrcDataLen = pFrameInfo.nFrameLen;
            //                stConverPixelParam.enSrcPixelType = pFrameInfo.enPixelType;
            //                stConverPixelParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed;//在此处选择需要转换的目标类型
            //                stConverPixelParam.pDstBuffer = pBufForSaveImage;
            //                stConverPixelParam.nDstBufferSize = (uint)(pFrameInfo.nWidth * pFrameInfo.nHeight * 3 + 2048);
            //                m_pMyCamera.MV_CC_ConvertPixelType_NET(ref stConverPixelParam);
            //                m_Image.GenImageInterleaved(pBufForSaveImage, "rgb", (int)pFrameInfo.nWidth, (int)pFrameInfo.nHeight, 0, "byte", (int)pFrameInfo.nWidth, (int)pFrameInfo.nHeight, 0, 0, -1, 0);
            //                //释放指针
            //                Marshal.FreeHGlobal(pBufForSaveImage);
            //            }
            //        }

            //        imageoutput.OutPutImage(m_Image);
            //    }
            //    catch (System.Exception ex)
            //    {
            //        //savelog.SaveLog(ex, false);
            //    }
            //}
            //if (VisionTool_Setting.BMPImage_Enable)
            if (true)
            {
                if (m_BufForDriver == IntPtr.Zero || pFrameInfo.nFrameLen > m_nBufSizeForDriver)
                {
                    if (m_BufForDriver != IntPtr.Zero)
                    {
                        Marshal.Release(m_BufForDriver);
                        m_BufForDriver = IntPtr.Zero;
                    }
                    m_BufForDriver = Marshal.AllocHGlobal((Int32)pFrameInfo.nFrameLen);
                    if (m_BufForDriver == IntPtr.Zero)
                    {
                        //Log.Instance.Debug("取像指针为空");
                        return;
                    }
                    m_nBufSizeForDriver = pFrameInfo.nFrameLen;
                }
                //m_stFrameInfo = stFrameInfo.stFrameInfo;
                CopyMemory(m_BufForDriver, pData, pFrameInfo.nFrameLen);
                // ch:转换像素格式 | en:Convert Pixel Format
                stConvertInfo.nWidth = pFrameInfo.nWidth;
                stConvertInfo.nHeight = pFrameInfo.nHeight;
                stConvertInfo.enSrcPixelType = pFrameInfo.enPixelType;
                stConvertInfo.pSrcData = pData;
                stConvertInfo.nSrcDataLen = pFrameInfo.nFrameLen;
                stConvertInfo.pDstBuffer = m_ConvertDstBuf;
                stConvertInfo.nDstBufferSize = m_nConvertDstBufLen;
                if (PixelFormat.Format8bppIndexed == m_bitmap.PixelFormat)
                {
                    stConvertInfo.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8;
                    m_pMyCamera.MV_CC_ConvertPixelType_NET(ref stConvertInfo);
                }
                else
                {
                    stConvertInfo.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_BGR8_Packed;
                    m_pMyCamera.MV_CC_ConvertPixelType_NET(ref stConvertInfo);
                }

                // ch:保存Bitmap数据 | en:Save Bitmap Data
                BitmapData bitmapData = m_bitmap.LockBits(new Rectangle(0, 0, stConvertInfo.nWidth, stConvertInfo.nHeight), ImageLockMode.ReadWrite, m_bitmap.PixelFormat);
                CopyMemory(bitmapData.Scan0, stConvertInfo.pDstBuffer, (UInt32)(bitmapData.Stride * m_bitmap.Height));
                m_bitmap.UnlockBits(bitmapData);
                autoResetEvent.Set();
                //imageoutput.OutPutBMP(m_bitmap);
            }
            //if(BMPImage_Enable)
            //{
            //    Bitmap bitmap;
            //    if (pFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8)
            //    {
            //        bitmap = new System.Drawing.Bitmap(pFrameInfo.nWidth, pFrameInfo.nHeight, pFrameInfo.nWidth, PixelFormat.Format8bppIndexed, pData);
            //        ColorPalette palette = bitmap.Palette;
            //        for (int Index = 0; Index <= byte.MaxValue; Index++)
            //        {
            //            palette.Entries[Index] = System.Drawing.Color.FromArgb(byte.MaxValue, Index, Index, Index);
            //        }
            //        bitmap.Palette = palette;
            //    }
            //    else
            //    {
            //        if (pFrameInfo.enPixelType == MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed)
            //        {
            //            //如果彩色图像是RGB8格式，则可以直接利用GenImageInterleaved算子来构建图像
            //            bitmap = new System.Drawing.Bitmap(pFrameInfo.nWidth, pFrameInfo.nHeight, pFrameInfo.nWidth * 3, PixelFormat.Format24bppRgb, pData);
            //        }
            //        else
            //        {
            //            //如果彩色图像不是RGB8格式，则需要将图像格式转换为RGB8。
            //            //IntPtr pBufForSaveImage = IntPtr.Zero;
            //            if (pBufForSaveImage == IntPtr.Zero)
            //            {
            //                pBufForSaveImage = Marshal.AllocHGlobal((int)(pFrameInfo.nWidth * pFrameInfo.nHeight * 3 + 2048));
            //                lastSize = pFrameInfo.nWidth * pFrameInfo.nHeight * 3 + 2048;
            //            }
            //            else if(lastSize != pFrameInfo.nWidth * pFrameInfo.nHeight * 3 + 2048)
            //            {
            //                Marshal.FreeHGlobal(pBufForSaveImage);
            //                pBufForSaveImage = Marshal.AllocHGlobal((int)(pFrameInfo.nWidth * pFrameInfo.nHeight * 3 + 2048));
            //            }
            //            MyCamera.MV_PIXEL_CONVERT_PARAM stConverPixelParam = new MyCamera.MV_PIXEL_CONVERT_PARAM();
            //            stConverPixelParam.nWidth = pFrameInfo.nWidth;
            //            stConverPixelParam.nHeight = pFrameInfo.nHeight;
            //            stConverPixelParam.pSrcData = pData;
            //            stConverPixelParam.nSrcDataLen = pFrameInfo.nFrameLen;
            //            stConverPixelParam.enSrcPixelType = pFrameInfo.enPixelType;
            //            stConverPixelParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed;//在此处选择需要转换的目标类型
            //            stConverPixelParam.pDstBuffer = pBufForSaveImage;
            //            stConverPixelParam.nDstBufferSize = (uint)(pFrameInfo.nWidth * pFrameInfo.nHeight * 3 + 2048);
            //            m_pMyCamera.MV_CC_ConvertPixelType_NET(ref stConverPixelParam);
            //            bitmap = new System.Drawing.Bitmap(pFrameInfo.nWidth, pFrameInfo.nHeight, pFrameInfo.nWidth * 3, PixelFormat.Format24bppRgb, pBufForSaveImage);
            //            //释放指针
            //            //Marshal.FreeHGlobal(pBufForSaveImage);
            //        }
            //    }

            //    imageoutput.OutPutBMP(bitmap);
            //    bitmap.Dispose();
            //}

        }

        // ch:像素类型是否为Mono格式 | en:If Pixel Type is Mono 
        private Boolean IsMono(UInt32 enPixelType)
        {
            switch (enPixelType)
            {
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono1p:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono2p:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono4p:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8_Signed:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10_Packed:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12_Packed:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono14:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono16:
                    return true;
                default:
                    return false;
            }
        }

        // ch:取图前的必要操作步骤 | en:Necessary operation before grab
        private Int32 NecessaryOperBeforeGrab()
        {
            // ch:取图像宽 | en:Get Iamge Width
            MyCamera.MVCC_INTVALUE_EX stWidth = new MyCamera.MVCC_INTVALUE_EX();
            int nRet = m_pMyCamera.MV_CC_GetIntValueEx_NET("Width", ref stWidth);
            if (MyCamera.MV_OK != nRet)
            {
                ShowErrorMsg("Get Width Info Fail!", nRet);
                return nRet;
            }
            // ch:取图像高 | en:Get Iamge Height
            MyCamera.MVCC_INTVALUE_EX stHeight = new MyCamera.MVCC_INTVALUE_EX();
            nRet = m_pMyCamera.MV_CC_GetIntValueEx_NET("Height", ref stHeight);
            if (MyCamera.MV_OK != nRet)
            {
                ShowErrorMsg("Get Height Info Fail!", nRet);
                return nRet;
            }
            // ch:取像素格式 | en:Get Pixel Format
            MyCamera.MVCC_ENUMVALUE stPixelFormat = new MyCamera.MVCC_ENUMVALUE();
            nRet = m_pMyCamera.MV_CC_GetEnumValue_NET("PixelFormat", ref stPixelFormat);
            if (MyCamera.MV_OK != nRet)
            {
                ShowErrorMsg("Get Pixel Format Fail!", nRet);
                return nRet;
            }

            // ch:设置bitmap像素格式，申请相应大小内存 | en:Set Bitmap Pixel Format, alloc memory
            if ((Int32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Undefined == stPixelFormat.nCurValue)
            {
                ShowErrorMsg("Unknown Pixel Format!", MyCamera.MV_E_UNKNOW);
                return MyCamera.MV_E_UNKNOW;
            }
            else if (IsMono(stPixelFormat.nCurValue))
            {
                m_bitmapPixelFormat = PixelFormat.Format8bppIndexed;

                if (IntPtr.Zero != m_ConvertDstBuf)
                {
                    Marshal.Release(m_ConvertDstBuf);
                    m_ConvertDstBuf = IntPtr.Zero;
                }

                // Mono8为单通道
                m_nConvertDstBufLen = (UInt32)(stWidth.nCurValue * stHeight.nCurValue);
                m_ConvertDstBuf = Marshal.AllocHGlobal((Int32)m_nConvertDstBufLen);
                if (IntPtr.Zero == m_ConvertDstBuf)
                {
                    ShowErrorMsg("Malloc Memory Fail!", MyCamera.MV_E_RESOURCE);
                    return MyCamera.MV_E_RESOURCE;
                }
            }
            else
            {
                m_bitmapPixelFormat = PixelFormat.Format24bppRgb;

                if (IntPtr.Zero != m_ConvertDstBuf)
                {
                    Marshal.FreeHGlobal(m_ConvertDstBuf);
                    m_ConvertDstBuf = IntPtr.Zero;
                }

                // RGB为三通道
                m_nConvertDstBufLen = (UInt32)(3 * stWidth.nCurValue * stHeight.nCurValue);
                m_ConvertDstBuf = Marshal.AllocHGlobal((Int32)m_nConvertDstBufLen);
                if (IntPtr.Zero == m_ConvertDstBuf)
                {
                    ShowErrorMsg("Malloc Memory Fail!", MyCamera.MV_E_RESOURCE);
                    return MyCamera.MV_E_RESOURCE;
                }
            }

            // 确保释放保存了旧图像数据的bitmap实例，用新图像宽高等信息new一个新的bitmap实例
            if (null != m_bitmap)
            {
                m_bitmap.Dispose();
                m_bitmap = null;
            }
            m_bitmap = new Bitmap((Int32)stWidth.nCurValue, (Int32)stHeight.nCurValue, m_bitmapPixelFormat);

            // ch:Mono8格式，设置为标准调色板 | en:Set Standard Palette in Mono8 Format
            if (PixelFormat.Format8bppIndexed == m_bitmapPixelFormat)
            {
                ColorPalette palette = m_bitmap.Palette;
                for (int i = 0; i < palette.Entries.Length; i++)
                {
                    palette.Entries[i] = Color.FromArgb(i, i, i);
                }
                m_bitmap.Palette = palette;
            }

            return MyCamera.MV_OK;
        }
        // ch:显示错误信息 | en:Show error message
        static void ShowErrorMsg(string csMessage, int nErrorNum)
        {
            string errorMsg;
            if (nErrorNum == 0)
            {
                errorMsg = csMessage;
            }
            else
            {
                errorMsg = csMessage + ": Error =" + String.Format("{0:X}", nErrorNum);
            }

            switch (nErrorNum)
            {
                case MyCamera.MV_E_HANDLE: errorMsg += " Error or invalid handle "; break;
                case MyCamera.MV_E_SUPPORT: errorMsg += " Not supported function "; break;
                case MyCamera.MV_E_BUFOVER: errorMsg += " Cache is full "; break;
                case MyCamera.MV_E_CALLORDER: errorMsg += " Function calling order error "; break;
                case MyCamera.MV_E_PARAMETER: errorMsg += " Incorrect parameter "; break;
                case MyCamera.MV_E_RESOURCE: errorMsg += " Applying resource failed "; break;
                case MyCamera.MV_E_NODATA: errorMsg += " No data "; break;
                case MyCamera.MV_E_PRECONDITION: errorMsg += " Precondition error, or running environment changed "; break;
                case MyCamera.MV_E_VERSION: errorMsg += " Version mismatches "; break;
                case MyCamera.MV_E_NOENOUGH_BUF: errorMsg += " Insufficient memory "; break;
                case MyCamera.MV_E_UNKNOW: errorMsg += " Unknown error "; break;
                case MyCamera.MV_E_GC_GENERIC: errorMsg += " General error "; break;
                case MyCamera.MV_E_GC_ACCESS: errorMsg += " Node accessing condition error "; break;
                case MyCamera.MV_E_ACCESS_DENIED: errorMsg += " No permission "; break;
                case MyCamera.MV_E_BUSY: errorMsg += " Device is busy, or network disconnected "; break;
                case MyCamera.MV_E_NETER: errorMsg += " Network error "; break;
            }

            MessageBox.Show(errorMsg, "PROMPT");
        }
    }
}
